package main

import (
	"bufio"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// 定义一个结构体用于JSON示例
type Person4 struct {
	Name    string `json:"name"`
	Age     int    `json:"age"`
	Address string `json:"address"`
}

func main() {
	// ==========================================
	// 基本文件操作
	// ==========================================

	// 创建文件
	file, err := os.Create("test.txt")
	if err != nil {
		fmt.Println("创建文件错误:", err)
		return
	}
	defer file.Close() // 确保文件最后被关闭

	// 写入字符串
	content := "Hello, Go File Operations!\n这是第二行内容。"
	_, err = file.WriteString(content)
	if err != nil {
		fmt.Println("写入文件错误:", err)
		return
	}

	fmt.Println("文件写入成功")

	// ==========================================
	// 读取文件
	// ==========================================

	// 方法1：一次性读取整个文件
	data, err := os.ReadFile("test.txt")
	if err != nil {
		fmt.Println("读取文件错误:", err)
		return
	}
	fmt.Printf("\n一次性读取的内容:\n%s\n", string(data))

	// 方法2：使用Read方法逐块读取
	file, err = os.Open("test.txt")
	if err != nil {
		fmt.Println("打开文件错误:", err)
		return
	}
	defer file.Close()

	buffer := make([]byte, 1024)
	fmt.Println("\n逐块读取的内容:")
	for {
		n, err := file.Read(buffer)
		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Println("读取错误:", err)
			return
		}
		fmt.Print(string(buffer[:n]))
	}

	// ==========================================
	// 使用bufio进行缓冲读写
	// ==========================================

	// 创建文件用于bufio示例
	bufFile, err := os.Create("bufio_test.txt")
	if err != nil {
		fmt.Println("创建文件错误:", err)
		return
	}
	defer bufFile.Close()

	// 创建带缓冲的写入器
	writer := bufio.NewWriter(bufFile)

	// 写入多行内容
	lines := []string{
		"这是第一行",
		"这是第二行",
		"这是第三行",
	}

	for _, line := range lines {
		_, err := writer.WriteString(line + "\n")
		if err != nil {
			fmt.Println("写入错误:", err)
			return
		}
	}

	// 刷新缓冲区，确保所有数据都写入文件
	err = writer.Flush()
	if err != nil {
		fmt.Println("刷新缓冲区错误:", err)
		return
	}

	// 使用bufio读取文件
	bufFile, err = os.Open("bufio_test.txt")
	if err != nil {
		fmt.Println("打开文件错误:", err)
		return
	}
	defer bufFile.Close()

	// 创建带缓冲的读取器
	reader := bufio.NewReader(bufFile)

	fmt.Println("\nbufio读取的内容:")
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Println("读取错误:", err)
			return
		}
		fmt.Print(line)
	}

	// ==========================================
	// 文件和目录操作
	// ==========================================

	// 创建目录
	err = os.Mkdir("testdir", 0755)
	if err != nil && !os.IsExist(err) {
		fmt.Println("创建目录错误:", err)
		return
	}

	// 创建多级目录
	err = os.MkdirAll("testdir/subdir/subsubdir", 0755)
	if err != nil && !os.IsExist(err) {
		fmt.Println("创建多级目录错误:", err)
		return
	}

	// 遍历目录
	fmt.Println("\n遍历目录内容:")
	err = filepath.Walk("testdir", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		fmt.Printf("路径: %s, 是否是目录: %t\n", path, info.IsDir())
		return nil
	})
	if err != nil {
		fmt.Println("遍历目录错误:", err)
		return
	}

	// ==========================================
	// CSV文件操作
	// ==========================================

	// 创建CSV文件
	csvFile, err := os.Create("data.csv")
	if err != nil {
		fmt.Println("创建CSV文件错误:", err)
		return
	}
	defer csvFile.Close()

	// 创建CSV写入器
	csvWriter := csv.NewWriter(csvFile)
	defer csvWriter.Flush()

	// 写入CSV数据
	records := [][]string{
		{"姓名", "年龄", "城市"},
		{"张三", "25", "北京"},
		{"李四", "30", "上海"},
		{"王五", "35", "广州"},
	}

	for _, record := range records {
		err := csvWriter.Write(record)
		if err != nil {
			fmt.Println("写入CSV记录错误:", err)
			return
		}
	}

	// 读取CSV文件
	csvFile, err = os.Open("data.csv")
	if err != nil {
		fmt.Println("打开CSV文件错误:", err)
		return
	}
	defer csvFile.Close()

	// 创建CSV读取器
	csvReader := csv.NewReader(csvFile)

	fmt.Println("\nCSV文件内容:")
	for {
		record, err := csvReader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Println("读取CSV记录错误:", err)
			return
		}
		fmt.Println(strings.Join(record, " | "))
	}

	// ==========================================
	// JSON文件操作
	// ==========================================

	// 创建Person对象
	people := []Person4{
		{"张三", 25, "北京"},
		{"李四", 30, "上海"},
		{"王五", 35, "广州"},
	}

	// 将对象转换为JSON并写入文件
	jsonData, err := json.MarshalIndent(people, "", "    ")
	if err != nil {
		fmt.Println("JSON编码错误:", err)
		return
	}

	err = ioutil.WriteFile("data.json", jsonData, 0644)
	if err != nil {
		fmt.Println("写入JSON文件错误:", err)
		return
	}

	// 读取JSON文件
	jsonFile, err := ioutil.ReadFile("data.json")
	if err != nil {
		fmt.Println("读取JSON文件错误:", err)
		return
	}

	var loadedPeople []Person4
	err = json.Unmarshal(jsonFile, &loadedPeople)
	if err != nil {
		fmt.Println("JSON解码错误:", err)
		return
	}

	fmt.Println("\nJSON文件内容:")
	for _, person := range loadedPeople {
		fmt.Printf("姓名: %s, 年龄: %d, 地址: %s\n", person.Name, person.Age, person.Address)
	}

	// ==========================================
	// 文件权限和模式
	// ==========================================

	// 创建只读文件
	readOnlyFile, err := os.OpenFile("readonly.txt",
		os.O_CREATE|os.O_WRONLY,
		0444) // 只读权限
	if err != nil {
		fmt.Println("创建只读文件错误:", err)
		return
	}
	readOnlyFile.Close()

	// 修改文件权限
	err = os.Chmod("readonly.txt", 0644)
	if err != nil {
		fmt.Println("修改文件权限错误:", err)
		return
	}

	// ==========================================
	// 清理测试文件
	// ==========================================

	// 删除创建的文件和目录
	os.Remove("test.txt")
	os.Remove("bufio_test.txt")
	os.Remove("data.csv")
	os.Remove("data.json")
	os.Remove("readonly.txt")
	os.RemoveAll("testdir")

	// ==========================================
	// 练习
	// ==========================================

	// 1. 创建一个程序，统计文本文件中的单词数量

	// 2. 实现一个简单的文件复制功能

	// 3. 创建一个程序，递归列出指定目录下的所有文件

	// 4. 实现一个配置文件读写程序（支持JSON或INI格式）

	// 5. 创建一个日志记录器，将日志写入文件
}

// ==========================================
// 练习参考实现
// ==========================================

// 1. 统计单词数量
func countWords(filename string) (int, error) {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return 0, err
	}

	words := strings.Fields(string(content))
	return len(words), nil
}

// 2. 文件复制
func copyFile(src, dst string) error {
	// 打开源文件
	sourceFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sourceFile.Close()

	// 创建目标文件
	destFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer destFile.Close()

	// 复制内容
	_, err = io.Copy(destFile, sourceFile)
	return err
}

// 3. 递归列出文件
func listFiles(path string) error {
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		fmt.Printf("%s: %d bytes\n", path, info.Size())
		return nil
	})
}

// 4. 配置文件结构
type Config struct {
	ServerName string `json:"server_name"`
	Port       int    `json:"port"`
	Database   struct {
		Host     string `json:"host"`
		Username string `json:"username"`
		Password string `json:"password"`
	} `json:"database"`
}

// 保存配置
func saveConfig(filename string, config Config) error {
	data, err := json.MarshalIndent(config, "", "    ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filename, data, 0644)
}

// 加载配置
func loadConfig(filename string) (Config, error) {
	var config Config
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return config, err
	}
	err = json.Unmarshal(data, &config)
	return config, err
}

// 5. 简单日志记录器
type Logger struct {
	file *os.File
}

func NewLogger(filename string) (*Logger, error) {
	file, err := os.OpenFile(filename,
		os.O_CREATE|os.O_WRONLY|os.O_APPEND,
		0644)
	if err != nil {
		return nil, err
	}
	return &Logger{file: file}, nil
}

func (l *Logger) Log(message string) error {
	_, err := fmt.Fprintf(l.file, "%s: %s\n",
		time.Now().Format("2006-01-02 15:04:05"),
		message)
	return err
}

func (l *Logger) Close() error {
	return l.file.Close()
}
